﻿using System;
using MathService.Values;

namespace MathService.Statistic.RandomNumbers
{
    /// <summary>Генератор случайных чисел</summary>
    [Serializable]
    public abstract class RandomGenerator : IValueRead<double>
    {
        /// <summary>Датчик случайных чисел с равномерным распределением</summary>
        protected static readonly LazyValue<Random> SystemRandomGenerator =
            new LazyValue<Random>(() => new Random(DateTime.Now.TimeOfDay.Milliseconds));

        /* ------------------------------------------------------------------------------------------ */

        /// <summary>Дисперсия</summary>
        protected double f_sigma = 1;
        /// <summary>Математическое ожидание</summary>
        protected double f_mu;

        /* ------------------------------------------------------------------------------------------ */

        /// <summary>Дисперсия</summary>
        public double sigma { get { return f_sigma; } set { f_sigma = value; } }

        /// <summary>Математическое ожидание</summary>
        public double mu { get { return f_mu; } set { f_mu = value; } }

        /// <summary>Случайное значение</summary>
        public double Value { get { return GetValue(); } }

        /* ------------------------------------------------------------------------------------------ */

        protected RandomGenerator() { }

        protected RandomGenerator(double sigma) { f_sigma = sigma; }

        protected RandomGenerator(double sigma, double mu) { f_sigma = sigma; f_mu = mu; }

        /* ------------------------------------------------------------------------------------------ */

        public abstract double Distribution(double x);

        /// <summary>Новое случайное число</summary><returns>Случайное число</returns>
        protected double GetValue() { return GetValue(f_sigma, f_mu); }

        public double GetValue(double sigma, double m) { return GetNextValue() * sigma + m; }

        protected abstract double GetNextValue();

        /* ------------------------------------------------------------------------------------------ */

        public static implicit operator double(RandomGenerator rnd) { return rnd.GetValue(); }

        /* ------------------------------------------------------------------------------------------ */
    }

    public class TriangularRandomGenerator : RandomGenerator
    {
        private double f_a;
        private double f_b;

        public double a { get { return f_a; } set { if(Math.Abs(value - f_a) > double.Epsilon) SetAB(value, b); } }
        public double b { get { return f_b; } set { if(Math.Abs(value - f_b) > double.Epsilon) SetAB(a, value); } }

        public TriangularRandomGenerator(double a, double b)
            : base(mu: (a + b) / 2, sigma: (b - a) / Math.Sqrt(24))
        {
            f_a = a;
            f_b = b;
        }

        public void SetAB(double a, double b)
        {
            f_a = a;
            f_b = b;
            sigma = (b - a) / Math.Sqrt(24);
            mu = (a + b) / 2;
        }

        public override double Distribution(double x) { return Distributions.Triangular(x, f_a, f_b); }

        protected override double GetNextValue()
        {
            //var rnd = SystemRandomGenerator.Value;
            throw new NotImplementedException();
            //return rnd.NextDouble() + rnd.NextDouble();
        }
    }
}
